/* $Id:race.cc $ */
/*
   Copyright (C) 2007 by Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>
   Part of the Moros Project http://moros.sourceforge.net/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#define DEBUG_ROUTINE "race"

#include <sstream>
#include <fstream>
#include "../general/util.h"
#include "../general/log.h"
#include "../general/channel.h"
#include "race.h"
#include "item.h"
#include "aging.h"
#include "background.h"
#include "skill.h"
#include "../general/general.h"

race::race() {
    name="";
    description="";
    size=0;
    special=map<int,class action_level>();
    maxSpecial=0;
    weapons=map<string,class material>();
    age_percentage=0;
    aging=0;
    reach=0;
    background=map<string,class background_level>();
    skill=map<string,class skill_level>();
    armor=0;
    unit=map<string,class unit>();
    culture=map<string,class culture>();
}

// Field : name

const string race::getName() const { return name; }
void race::setName(const string v) { name=v; }

// Field : description

const string race::getDescription() const { return description; }
void race::setDescription(const string v) { description=v; }

// Field : size

const int race::getSize() const { return size; }
void race::setSize(const int v) { size=v; }

// Field : special

class action_level& race::getSpecial(const int v) { return special[v]; }
map<int,class action_level>& race::listSpecial() { return special; }
void race::setSpecial(class action_level &v) {
    if (v.getNr()==0) v.setNr(++maxSpecial);
    special[v.getNr()]=v;
}
void race::delSpecial(const int v) { special.erase(v); }
const bool race::isSpecial(const int v) const { return special.count(v)>0; }

// Field : weapons

class material& race::getWeapons(const string v) { return weapons[v]; }
list<class material>& race::listWeapons() {
    static list<class material> res;
    res.clear();
    loopMap(weapons,v,class material) {
        res.push_back(*v);
    }
    res.sort();
    return res;
}
void race::setWeapons(class material &v) {
    weapons[v.getItem().getName()]=v;
}
void race::delWeapons(const string v) { weapons.erase(v); }
const bool race::isWeapons(const string v) const { return weapons.count(v)>0; }

// Field : age_percentage

const int race::getAge_percentage() const { return age_percentage; }
void race::setAge_percentage(const int v) { age_percentage=v; }

// Field : aging

class aging& race::getAging() const { if (aging==0) throw nullpointer(); return *aging; }
void race::setAging(class aging &v) { aging=&v; }

// Field : reach

const int race::getReach() const { return reach; }
void race::setReach(const int v) { reach=v; }

// Field : background

class background_level& race::getBackground(const string v) { return background[v]; }
list<class background_level>& race::listBackground() {
    static list<class background_level> res;
    res.clear();
    loopMap(background,v,class background_level) {
        res.push_back(*v);
    }
    res.sort();
    return res;
}
void race::setBackground(class background_level &v) {
    background[v.getBackground().getName()]=v;
}
void race::delBackground(const string v) { background.erase(v); }
const bool race::isBackground(const string v) const { return background.count(v)>0; }

// Field : skill

class skill_level& race::getSkill(const string v) { return skill[v]; }
map<string,class skill_level>& race::listSkill() { return skill; }
void race::setSkill(class skill_level &v) {
    skill[v.getSkill().getName()]=v;
}
void race::delSkill(const string v) { skill.erase(v); }
const bool race::isSkill(const string v) const { return skill.count(v)>0; }

// Field : armor

const int race::getArmor() const { return armor; }
void race::setArmor(const int v) { armor=v; }

// Field : unit

class unit& race::getUnit(const string v) { return unit[v]; }
map<string,class unit>& race::listUnit() { return unit; }
void race::setUnit(class unit &v) {
    if (v.getName()=="") throw unnamed();
    unit[v.getName()]=v;
}
void race::delUnit(const string v) { unit.erase(v); }
const bool race::isUnit(const string v) const { return unit.count(v)>0; }

// Field : culture

class culture& race::getCulture(const string v) { return culture[v]; }
map<string,class culture>& race::listCulture() { return culture; }
void race::setCulture(class culture &v) {
    if (v.getName()=="") throw unnamed();
    culture[v.getName()]=v;
}
void race::delCulture(const string v) { culture.erase(v); }
const bool race::isCulture(const string v) const { return culture.count(v)>0; }

void race::save(class channel &ch) {
    ch.write("race", "");
    ch.write("n", getName());
    ch.write("d", getDescription());
    ch.write("s", getSize());
    loopRaceSpecial(this, s_special) {
        s_special->save(ch);
    }
    loopRaceWeapons(this, s_weapons) {
        s_weapons->save(ch);
    }
    ch.write("a", getAge_percentage());
    ch.write("ag", getAging().getName());
    ch.write("r", getReach());
    loopRaceBackground(this, s_background) {
        s_background->save(ch);
    }
    loopRaceSkill(this, s_skill) {
        s_skill->save(ch);
    }
    ch.write("ar", getArmor());
    loopRaceUnit(this, s_unit) {
        s_unit->save(ch);
    }
    loopRaceCulture(this, s_culture) {
        s_culture->save(ch);
    }
}

void race::load(class channel &ch) {
    if (ch.key=="n" || ch.key=="name") { setName(ch.value); ch.next(); }
    if (ch.key=="d" || ch.key=="description") { setDescription(ch.value); ch.next(); }
    if (ch.key=="s" || ch.key=="size") { setSize(atoi(ch.value.c_str())); ch.next(); }
    while (ch.key=="action_level" || ch.key=="special") {
        ch.next();
        class action_level rec;
        rec.load(ch);
        setSpecial(rec);
    }
    while (ch.key=="material" || ch.key=="weapons") {
        ch.next();
        class material rec;
        rec.load(ch);
        setWeapons(rec);
    }
    if (ch.key=="a" || ch.key=="age_percentage") { setAge_percentage(atoi(ch.value.c_str())); ch.next(); }
    if (ch.key=="ag" || ch.key=="aging") {
        if (!aging_repo.isAging(ch.value)) {
            dbg_state("link unknown aging %s", ch.value.c_str());
            class aging rec;
            rec.setName(ch.value);
            aging_repo.setAging(rec);
        }
        setAging(aging_repo.getAging(ch.value));
        ch.next();
    }
    if (ch.key=="r" || ch.key=="reach") { setReach(atoi(ch.value.c_str())); ch.next(); }
    while (ch.key=="background_level" || ch.key=="background") {
        ch.next();
        class background_level rec;
        rec.load(ch);
        setBackground(rec);
    }
    while (ch.key=="skill_level" || ch.key=="skill") {
        ch.next();
        class skill_level rec;
        rec.load(ch);
        setSkill(rec);
    }
    if (ch.key=="ar" || ch.key=="armor") { setArmor(atoi(ch.value.c_str())); ch.next(); }
    while (ch.key=="unit" || ch.key=="unit") {
        ch.next();
        class unit rec;
        rec.load(ch);
        setUnit(rec);
    }
    while (ch.key=="culture" || ch.key=="culture") {
        ch.next();
        class culture rec;
        rec.load(ch);
        setCulture(rec);
    }
}

void race::xml(ofstream &f, int l, int r) {
    f << ncpy(l, "  ") << "<race name=\"" << xml_encode(getName()) <<
    "\" description=\"" << xml_encode(getDescription()) <<
    "\" size=\"" << getSize() <<
    "\" age_percentage=\"" << getAge_percentage() <<
    "\" reach=\"" << getReach() <<
    "\" armor=\"" << getArmor() <<
    "\">" << endl;
    if (r<2) try {
        getAging().xml(f,l+1,r+1);
    } catch (nullpointer n) {}
    if (r==0) {
        loopRaceSpecial(this, s_special) {
            s_special->xml(f,l+1);
        }
        loopRaceWeapons(this, s_weapons) {
            s_weapons->xml(f,l+1);
        }
        loopRaceBackground(this, s_background) {
            s_background->xml(f,l+1);
        }
        loopRaceSkill(this, s_skill) {
            s_skill->xml(f,l+1);
        }
        loopRaceUnit(this, s_unit) {
            s_unit->xml(f,l+1);
        }
        loopRaceCulture(this, s_culture) {
            s_culture->xml(f,l+1);
        }
    }
    f << ncpy(l, "  ") << "</race>" << endl;
}

// Repository

raceRepository race_repo;

class race& raceRepository::getRace(const string v) { return races[v]; }
void raceRepository::setRace(class race& v) {
    if (v.getName()=="") throw unnamed();
    races[v.getName()]=v;
}
map<string,class race>& raceRepository::listRace() { return races; }
void raceRepository::delRace(const string v) { races.erase(v); }
const bool raceRepository::isRace(const string v) const { return races.count(v)>0; }
void raceRepository::save(class channel &ch) {
    loopRaces(rec) {
        rec->save(ch);
    }
}

bool raceRepository::load(class channel &ch) {
    if (ch.key=="race") {
        ch.next();
        class race rec;
        rec.load(ch);
        setRace(rec);
        return true;
    }
    return false;
}
